import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';

import 'baidu_speech_constant.dart';
import 'baidu_speech_error.dart';

/*
  百度语音识别封装
  ios、android事件全部分发到dart层
  dart层统一处理平台返回事件
  使用前必须调用setClientConfig配置数据
 */
class BaiduSpeech {
  //工厂模式
  factory BaiduSpeech() => _getInstance();
  static BaiduSpeech _instance;

  static BaiduSpeech get instance => _getInstance();

  BaiduSpeech._internal() {
    _init();
  }

  static BaiduSpeech _getInstance() {
    if (_instance == null) {
      _instance = new BaiduSpeech._internal();
    }
    return _instance;
  }

  final String channelName = 'com.ziqiangwanqiang.baidu.speech.method';
  final String eventChannelName = 'com.ziqiangwanqiang.baidu.speech.event';
  MethodChannel methodChannel;
  EventChannel eventChannel;

  //用于ios的配置，安卓需要在安卓工程配置
  String apiKey;
  String secretKey;
  String appId;

  //是否正在讲话
  bool _isSpeaking = false;

  //ios平台是否已经准备好配置可以讲话
  bool get _isInitConfig => (Platform.isIOS && appId != null && secretKey != null && apiKey != null) || Platform.isAndroid;

  //语音识别结果订阅流管理者
  StreamController<String> _speechRecognitionStreamController;

  //语音识别结果订阅流
  Stream<String> speechRecognitionStream;

  //音量大小订阅流管理者
  StreamController<int> _voiceLevelStreamController;

  //音量大小订阅流
  Stream<int> voiceLevelStream;

  //连续上屏订阅流管理者
  StreamController<String> _flushDataStreamController;

  //连续上屏订阅流
  Stream<String> flushDataStream;

  //错误订阅流管理
  StreamController<BaiduSpeechErrorResponse> _errEventStreamController;

  //错误订阅流
  Stream<BaiduSpeechErrorResponse> errEventStream;

  //语音状态订阅管理
  StreamController<String> _statusStreamController;

  //语音状态订阅流
  Stream<String> statusEventStream;

  //初始化
  _init() {
    methodChannel = MethodChannel(channelName);
    eventChannel = EventChannel(eventChannelName);

    _speechRecognitionStreamController = StreamController<String>();
    speechRecognitionStream = _speechRecognitionStreamController.stream.asBroadcastStream();

    _voiceLevelStreamController = StreamController<int>();
    voiceLevelStream = _voiceLevelStreamController.stream.asBroadcastStream();

    _flushDataStreamController = StreamController<String>();
    flushDataStream = _flushDataStreamController.stream.asBroadcastStream();

    _errEventStreamController = StreamController<BaiduSpeechErrorResponse>();
    errEventStream = _errEventStreamController.stream.asBroadcastStream();

    _statusStreamController = StreamController<String>();
    statusEventStream = _statusStreamController.stream.asBroadcastStream();

    _addEventListener();
  }

  //开始讲话
  start() async {
    if (!_isInitConfig) {
      throw 'baidu speech must before call start by setConfig on platform IOS!';
    }
    if (_isSpeaking) return;

    _isSpeaking = true;

    _statusStreamController.add(BaiduSpeechConstant.ASR_PREPARING);

    await methodChannel.invokeMethod<String>('start');
  }

  //结束讲话
  end() async {
    if (!_isSpeaking) return;

    await methodChannel.invokeMethod<String>('end');
    _isSpeaking = false;
  }

  //事件监听
  _addEventListener() {
    eventChannel.receiveBroadcastStream().listen(
      (dynamic data) {
        if (Platform.isIOS) {
          _handleIOSEvent(data);
        } else if (Platform.isAndroid) {
          _handleAndroidEvent(data);
        }
      },
      onError: (dynamic error) {},
    );
  }

  //设置配置
  setClientConfig({
    @required String apiKey,
    @required String secretKey,
    @required String appId,
  }) async {
    this.apiKey = apiKey;
    this.secretKey = secretKey;
    this.appId = appId;

    await methodChannel.invokeMethod('setClientConfig', {
      'API_KEY': apiKey,
      'SECRET_KEY': secretKey,
      'APP_ID': apiKey,
    });
  }

  //处理ios事件
  _handleIOSEvent(dynamic eventData) {
    var code = eventData['code'] as int;
    var errCode = eventData['errCode'];
    var data = eventData['data'];

    if (errCode != 0) {
      _isSpeaking = false;
      _errEventStreamController.add(
        BaiduSpeechErrorCode.getErrorByCode(errCode, TargetPlatform.iOS),
      );
    } else {
      switch (code) {
        case BaiduSpeechConstant.EVoiceRecognitionClientWorkStatusStartWorkIng:
          log("用户可以开始说话");

          _statusStreamController.add(BaiduSpeechConstant.ASR_READY);

          break;
        case BaiduSpeechConstant.EVoiceRecognitionClientWorkStatusStart:
          log("检测到用户开始说话");

          _statusStreamController.add(BaiduSpeechConstant.ASR_BEGIN);
          break;
        case BaiduSpeechConstant.EVoiceRecognitionClientWorkStatusEnd:
          log("本地声音采集结束结束，等待识别结果返回并结束录音");

          _statusStreamController.add(BaiduSpeechConstant.ASR_END);
          break;
        case BaiduSpeechConstant.EVoiceRecognitionClientWorkStatusFlushData:
          var word = data['results_recognition'][0];

          _flushDataStreamController.add(word);
          break;
        case BaiduSpeechConstant.EVoiceRecognitionClientWorkStatusFinish:
          var word = data['results_recognition'][0];
          log("语音识别功能完成，服务器返回正确结果:$word");

          _statusStreamController.add(BaiduSpeechConstant.ASR_FINISH);
          _speechRecognitionStreamController.add(word);
          break;
        case BaiduSpeechConstant.EVoiceRecognitionClientWorkStatusMeterLevel:
          _voiceLevelStreamController.add(data);
          break;
        case BaiduSpeechConstant.EVoiceRecognitionClientWorkStatusCancel:
          log("用户取消");
          break;
        case BaiduSpeechConstant.EVoiceRecognitionClientWorkStatusError:
          log("发生异常");
          break;
        case BaiduSpeechConstant.EVoiceRecognitionClientWorkStatusLoaded:
          log('引擎就绪');
          break;
        default:
          break;
      }
    }
  }

  String _androidFlushData = '';

  //处理安卓事件
  _handleAndroidEvent(dynamic eventData) {
    var name = eventData['name'];
    Map<String, dynamic> data;

    try {
      data = eventData == null ? {} : jsonDecode(eventData['params']);
    } catch (e) {}

    switch (name) {
      case BaiduSpeechConstant.CALLBACK_EVENT_ASR_READY:
        _androidFlushData = '';
        log("引擎准备就绪，可以开始说话");

        _statusStreamController.add(BaiduSpeechConstant.ASR_BEGIN);
        break;
      case BaiduSpeechConstant.CALLBACK_EVENT_ASR_BEGIN:
        log("检测到说话开始");

        _statusStreamController.add(BaiduSpeechConstant.ASR_BEGIN);
        break;
      case BaiduSpeechConstant.CALLBACK_EVENT_ASR_END:
        log("检测到说话结束");

        _statusStreamController.add(BaiduSpeechConstant.ASR_END);
        break;
      case BaiduSpeechConstant.CALLBACK_EVENT_ASR_FINISH:
        _isSpeaking = false;

        if (data['error'] == 0) {
          _speechRecognitionStreamController.add(_androidFlushData);
        } else {
          _errEventStreamController.add(
            BaiduSpeechErrorCode.getErrorByCode(data['errorCode'], TargetPlatform.android),
          );
        }
        break;
      case BaiduSpeechConstant.CALLBACK_EVENT_ASR_PARTIAL:
        _androidFlushData = data['results_recognition'][0];

        _flushDataStreamController.add(_androidFlushData);

        _statusStreamController.add(BaiduSpeechConstant.ASR_FINISH);
        break;
      case BaiduSpeechConstant.CALLBACK_EVENT_ASR_VOLUME:
        _voiceLevelStreamController.add(data['volume-percent']);
        break;
      case BaiduSpeechConstant.CALLBACK_EVENT_ASR_EXIT:
        log("识别结束，资源释放");
        break;
      case BaiduSpeechConstant.CALLBACK_EVENT_ASR_LOADED:
        log("离线模型加载成功");
        break;
      case BaiduSpeechConstant.CALLBACK_EVENT_ASR_UNLOADED:
        log("离线模型卸载成功");
        break;
      default:
        break;
    }
  }
}
